﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Xnaml.Demo {
	public abstract class Interpolator<T> {
		public Action<Interpolator<T>> Interpolated;
		protected bool active = false;
		protected double current = 1.0;
		protected double total = 1.0;
		protected bool smoothly = false;
		protected T start;
		protected T end;
		protected T currentval;

		public bool Active {
			get {
				return active;
			}
		}

		public bool Inactive {
			get {
				return !active;
			}
		}

		public bool Finished {
			get {
				return current == total;
			}
		}

		public T Ending {
			get {
				return end;
			}
		}

		public T Beginning {
			get {
				return start;
			}
		}

		public T Value {
			get {
				return currentval;
			}
			set {
				Force( value );
			}
		}

		public float Progress {
			get {
				return (float)( current / total );
			}
		}

		public double PreciseProgress {
			get {
				return current / total;
			}
		}

		public Interpolator ( ) {
			current = 0;
		}

		public Interpolator ( T value ) {
			start = end = currentval = value;
		}

		public void Start ( T startval, T endval ) {
			Start( startval, endval, 1000, false, null );
		}

		public void Start ( T startval, T endval, double ms ) {
			Start( startval, endval, ms, false, null );
		}

		public void Start ( T startval, T endval, bool smooth, double ms ) {
			Start( startval, endval, ms, smooth, null );
		}

		public void Start ( T startval, T endval, double ms, Action<Interpolator<T>> interpolated ) {
			Start( startval, endval, ms, false, interpolated );
		}

		public void Start ( T endval ) {
			Start( endval, 1000, false, null );
		}

		public void Start ( T endval, double ms ) {
			Start( endval, ms, false, null );
		}

		public void Start ( T endval, bool smooth, double ms ) {
			Start( endval, ms, smooth, null );
		}

		public void Start ( T endval, double ms, Action<Interpolator<T>> interpolated ) {
			Start( endval, ms, false, interpolated );
		}

		public void Start ( T startval, T endval, double ms, bool smooth, Action<Interpolator<T>> interpolated ) {
			currentval = start = startval;
			end = endval;
			if ( ms <= 0.0f ) {
				total = 1.0;
				current = 1.0;
				currentval = end;
				active = false;
				return;
			}
			total = ms;
			smoothly = smooth;
			current = 0;
			Interpolated = interpolated;
			active = true;
		}

		public void Start ( T endval, double ms, bool smooth, Action<Interpolator<T>> interpolated ) {
			start = currentval;
			end = endval;
			if ( ms <= 0.0f ) {
				total = 1.0;
				current = 1.0;
				currentval = end;
				active = false;
				return;
			}
			total = ms;
			smoothly = smooth;
			current = 0;
			Interpolated = interpolated;
			active = true;
		}

		public T Update ( GameTime gameTime ) {
			if ( active ) {
				current += gameTime.ElapsedGameTime.TotalMilliseconds;
				if ( current >= total ) {
					current = total;
					if ( Interpolated != null )
						Interpolated( this );
					active = false;
				}
				return currentval = Interpolate( );
			}
			return currentval;
		}

		public void Update ( GameTime gameTime, ref T into ) {
			if ( active ) {
				current += gameTime.ElapsedGameTime.TotalMilliseconds;
				if ( current >= total ) {
					current = total;
					if ( Interpolated != null )
						Interpolated( this );
					active = false;
				}
				currentval = Interpolate( );
			}
			into = currentval;
		}

		public T Peek ( GameTime gameTime ) {
			double saveCurrent = current;
			bool saveActive = active;
			T preserve = currentval;
			T nextValue = Update( gameTime );
			current = saveCurrent;
			active = saveActive;
			currentval = preserve;

			return nextValue;
		}

		public void Peek ( GameTime gameTime, ref T peek ) {
			double saveCurrent = current;
			bool saveActive = active;
			T preserve = currentval;

			peek = Update( gameTime );

			current = saveCurrent;
			active = saveActive;
			currentval = preserve;
		}

		public void Resume ( ) {
			active = true;
		}

		public void Pause ( ) {
			active = false;
		}

		public void Pause ( T pausevalue ) {
			currentval = pausevalue;
			active = false;
		}

		public void Force ( ) {
			current = total;
			currentval = end;
			active = false;
		}

		public void Force ( T newend ) {
			current = total;
			currentval = end = newend;
			active = false;
		}

		public void Reset ( ) {
			current = 0;
			currentval = start;
			active = false;
		}

		public void Restart ( ) {
			current = 0;
			currentval = start;
			active = false;
			Start( end );
		}

		public void RestartReverse ( ) {
			current = 0;
			currentval = start;
			active = false;
			Start( end, start, total );
		}

		protected abstract T Interpolate ( );

		public abstract T Interpolation ( double at );

		public static implicit operator T ( Interpolator<T> i ) {
			return i.Value;
		}

		public override string ToString ( ) {
			return currentval + " [ " + ( current / total ).ToString( "0.00000%" ) + " ]";
		}
	}
}
